package com.keithpower.freshdox;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BasicCExecuter extends BasicTestExecuter
{
    // String to look for in template file, to replace with code
    private static final String REPLACE_ME = "<<< CODE_HERE >>>";

    private static final String C_FILE = "jdt_temp.c";

    private static final String EXE_FILE = "jdt_temp.exe";

    public BasicCExecuter()
    {
	super();
	// TODO Auto-generated constructor stub
    }

    public boolean doTest(Test test)
    {
	String codeToRun = test.getCode();
	String condition = test.getConditionCode();
	if (condition.length() > 0)
	{
	    codeToRun += "\n" + prepareCondition(condition);
	    System.out.println(codeToRun);
	}

	if (writeCodeToFile(codeToRun))
	{
	    if (compile())
	    {
		int retCode = run();
		if (retCode == 0)
		{
		    return true;
		}
		else
		{
		    setErrorInfo(test, "Test failed");
		}
	    }
	}

	return false;
    }

    private int run()
    {
	// TODO get from config script or config param
	String command = EXE_FILE;

	String[] cmds = new String[3];
	if (((String) System.getProperties().get("os.name"))
		.startsWith("Windows"))
	{
	    cmds[0] = "cmd";
	    cmds[1] = "/c";
	    cmds[2] = command;
	}
	else
	{
	    cmds[0] = "/bin/sh";
	    cmds[1] = "-c";
	    cmds[2] = command;
	}

	int code = -1;

	try
	{
	    Process proc = Runtime.getRuntime().exec(cmds);
	    proc.waitFor();
	    code = proc.exitValue();
	    System.out.println("Ran " + code);
	}
	catch (IOException ex2)
	{
	    System.err.println("ExecService error: " + ex2);
	}
	catch (InterruptedException ex3)
	{
	    System.err
		    .println("ServiceEngineModule interrupted while waiting on app");
	}
	return code;
    }

    private boolean compile()
    {
	// TODO get from config script or config param
	String compileCommand = "compile.bat";

	String[] cmds = new String[3];
	if (((String) System.getProperties().get("os.name"))
		.startsWith("Windows"))
	{
	    cmds[0] = "cmd";
	    cmds[1] = "/c";
	    cmds[2] = compileCommand;
	}
	else
	{
	    cmds[0] = "/bin/sh";
	    cmds[1] = "-c";
	    cmds[2] = compileCommand;
	}

	try
	{
	    Process proc = Runtime.getRuntime().exec(cmds);
	    proc.waitFor();
	    System.out.println("Compiled " + proc.exitValue());
	    return true;
	}
	catch (IOException ex2)
	{
	    System.err.println("Error compiling: " + ex2);
	}
	catch (InterruptedException ex3)
	{
	    System.err.println("Interrupted while compiling test code");
	}

	return true;
    }

    /**
         * Load template from a file and insert the code to run
         * 
         * @param codeToRun
         *                The code to run
         * @return boolean specifying whether write succeeded
         */
    private boolean writeCodeToFile(String codeToRun)
    {
	String template = loadTemplate();
	String allCode = template.replaceFirst(REPLACE_ME, codeToRun);

	try
	{
	    BufferedWriter out = new BufferedWriter(new FileWriter(C_FILE));
	    out.write(allCode);
	    out.close();
	    return true;
	}
	catch (IOException ex)
	{
	    System.err.println("Error writing temporary code file: " + ex);
	    // TODO Auto-generated catch block
	    ex.printStackTrace();
	}
	return false;
    }

    private String loadTemplate()
    {
	String template = "#include <stdio.h>\n";
	template += "\n";
	template += "int main()\n";
	template += "{\n";
	template += REPLACE_ME + "\n";
	template += "}\n";
	return template;
    }

    /**
         * Wrap return around boolean evaluation in test code Eg. test code is:
         * callSomeMethod(); x==7;
         * 
         * Will become:
         * 
         * callSomeMethod(); return (x==7);
         * 
         * NOTE: this code does not consider the case of a ; embedded in a
         * string
         * 
         * @param conditionCode
         * @return String with prepared code
         */
    private String prepareCondition(String conditionCode)
    {
	conditionCode = conditionCode.trim();

	// If conditionCode doesn't end with a ; tack one on, else it will pick
        // wrong statement
	if (conditionCode.charAt(conditionCode.length() - 1) != ';')
	{
	    conditionCode += ';';
	}

	int lastSemiPos = conditionCode.lastIndexOf(';');
	int secondLastSemiPos = 0;
	if (lastSemiPos > 1)
	{
	    secondLastSemiPos = conditionCode.lastIndexOf(';', lastSemiPos - 1);
	    secondLastSemiPos++; // we want position just after 2nd last
                                        // semi
	}

	System.out.println(conditionCode + " : " + lastSemiPos + " - "
		+ secondLastSemiPos);
	String condition = conditionCode.substring(secondLastSemiPos,
		lastSemiPos).trim();
	String prepStr = conditionCode.substring(0, secondLastSemiPos);
	prepStr += "\nif(" + condition + "){ return 0; }else{ return 1; }";

	return prepStr;
    }

}
